/*
 * Copyright (C) 2009 Georgios J. Georgopoulos, All rights reserved.
 * 
 * This is free software; you can redistribute it and/or modify it under the
 * terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation; either version 3 of the License, or (at your option) any
 * later version.
 * 
 * This software is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
 * details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with this software; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA, or see the FSF
 * site: http://www.fsf.org.
 */
package org.gwt.mosaic.xul.client.ui;

import java.io.Serializable;
import java.util.Iterator;

import org.gwt.mosaic.ui.client.table.PagingScrollTable2;

import com.google.gwt.gen2.table.client.AbstractColumnDefinition;
import com.google.gwt.gen2.table.client.CellRenderer;
import com.google.gwt.gen2.table.client.ColumnDefinition;
import com.google.gwt.gen2.table.client.DefaultRowRenderer;
import com.google.gwt.gen2.table.client.DefaultTableDefinition;
import com.google.gwt.gen2.table.client.MutableTableModel;
import com.google.gwt.gen2.table.client.TableDefinition;
import com.google.gwt.gen2.table.client.TableModel;
import com.google.gwt.gen2.table.client.TableDefinition.AbstractCellView;
import com.google.gwt.gen2.table.client.TableModelHelper.Request;
import com.google.gwt.gen2.table.client.TableModelHelper.Response;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.HasAlignment;
import com.google.gwt.user.client.ui.HasHorizontalAlignment;
import com.google.gwt.user.client.ui.Widget;

/**
 * 
 * @author georgopoulos.georgios(at)gmail.com
 * 
 */
public class Table extends Container {
  private class InternalCellRenderer implements CellRenderer<Tablerow, String>,
      HasAlignment {
    private HorizontalAlignmentConstant hAlignment = HasAlignment.ALIGN_LEFT;
    private VerticalAlignmentConstant vAlignment = HasAlignment.ALIGN_MIDDLE;

    public HorizontalAlignmentConstant getHorizontalAlignment() {
      return hAlignment;
    }

    public VerticalAlignmentConstant getVerticalAlignment() {
      return vAlignment;
    }

    public void renderRowValue(Tablerow rowValue,
        ColumnDefinition<Tablerow, String> columnDef,
        AbstractCellView<Tablerow> view) {
      view.setHorizontalAlignment(hAlignment);
      view.setVerticalAlignment(vAlignment);
      view.setHTML(columnDef.getCellValue(rowValue));
    }

    public void setHorizontalAlignment(HorizontalAlignmentConstant align) {
      this.hAlignment = align;
    }

    public void setVerticalAlignment(VerticalAlignmentConstant align) {
      this.vAlignment = align;
    }

  }

  /**
   * An iterator that serves as the data source for table row requests.
   */
  private class InternalTableModel extends MutableTableModel<Tablerow> {

    @Override
    protected boolean onRowInserted(int beforeRow) {
      return true;
    }

    @Override
    protected boolean onRowRemoved(int row) {
      return true;
    }

    @Override
    protected boolean onSetRowValue(int row, Tablerow rowValue) {
      return true;
    }

    @Override
    public void requestRows(Request request,
        com.google.gwt.gen2.table.client.TableModel.Callback<Tablerow> callback) {

      if (tablerows == null) {
        tablerows = new Tablerows();
      }

      callback.onRowsReady(request, new Response<Tablerow>() {
        @Override
        public Iterator<Tablerow> getRowValues() {
          return new Iterator<Tablerow>() {
            private Iterator<Element> iter = null;

            public boolean hasNext() {
              if (iter == null) {
                iter = tablerows.elements.iterator();
              }
              return iter.hasNext();
            }

            public Tablerow next() {
              return (Tablerow) iter.next();
            }

            public void remove() {
              throw new RuntimeException("Operation not supported.");
            }
          };
        }
      });
    }

  }

  private static final long serialVersionUID = 700419591735538585L;
  private transient PagingScrollTable2<? extends Serializable> table;

  private Tablecols tablecols;

  private Tablerows tablerows;

  public Table() {
    super();
  }

  @Override
  public Element add(Element element, int index) {
    if (element instanceof Tablecols) {
      if (this.tablecols != null) {
        remove(this.tablecols);
      }
      this.tablecols = (Tablecols) element;
      return super.add(element, index);
    } else if (element instanceof Tablerows) {
      if (this.tablerows != null) {
        remove(this.tablerows);
      }
      this.tablerows = (Tablerows) element;
      return super.add(element, index);
    }
    return null;
  }

  @Override
  public Element remove(int index) {
    Element element = elements.get(index);
    if (element instanceof Tablecols) {
      this.tablecols = null;
      return super.remove(index);
    } else if (element instanceof Tablerows) {
      this.tablerows = null;
      return super.remove(index);
    }
    return null;
  }

  private TableDefinition<Tablerow> createTableDefinition() {
    DefaultTableDefinition<Tablerow> tableDef = new DefaultTableDefinition<Tablerow>();
    tableDef.setRowRenderer(new DefaultRowRenderer<Tablerow>(new String[] {
        "#cdcdcd", "#efefef"}));

    if (tablecols != null) {
      for (int i = 0, n = tablecols.elements.size(); i < n; ++i) {
        final int cell = i;
        final Tablecol tablecol = (Tablecol) tablecols.getElement(cell);
        AbstractColumnDefinition<Tablerow, String> colDef = new AbstractColumnDefinition<Tablerow, String>() {
          @Override
          public String getCellValue(Tablerow rowValue) {
            if (cell < rowValue.getElementCount()) {
              return ((Tablecell) rowValue.getElement(cell)).getLabel();
            } else {
              return null;
            }
          }

          @Override
          public void setCellValue(Tablerow rowValue, String cellValue) {
            ((Tablecell) rowValue.getElement(cell)).setLabel(cellValue);
          }
        };
        colDef.setHeader(0, tablecol.getLabel());
        InternalCellRenderer cellRenderer = new InternalCellRenderer();
        if ("end".equals(tablecol.getAlign())) {
          cellRenderer.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_RIGHT);
        } else if ("center".equals(tablecol.getAlign())) {
          cellRenderer.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_CENTER);
        }
        colDef.setCellRenderer(cellRenderer);

        tableDef.addColumnDefinition(colDef);
      }
    }

    return tableDef;
  }

  private TableModel<Tablerow> createTableModel() {
    return new InternalTableModel();
  }

  @Override
  protected Widget createUI() {
    table = new PagingScrollTable2<Tablerow>(createTableModel(),
        createTableDefinition());
    table.setEmptyTableWidget(new HTML("Empty!"));
    table.setPageSize(100);
    table.gotoFirstPage();

    return table;
  }

  public TableModel<? extends Serializable> getTableModel() {
    return table.getTableModel();
  }

}
